from exceptions import ValueError

from django import template
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType

from customtags.decorators import function_decorator
register = template.Library()
function = function_decorator(register)

from pirate_core.middleware import TYPE_KEY, OBJ_KEY, START_KEY, END_KEY, DIM_KEY, SCROLL_KEY, RETURN_KEY

'''
This file contains the tag responsible for creating useful urls within pp templates.
'''

@function
def pp_url(*args, **kwargs):
    '''
    This block tag will produce a url that will link to the designated view or pattern
    name, and then will optionally populate the request passed to that view with 
    either a specific ORM object, or a numerical range (start...end), as long as
    the pirate_core.url_middleware.UrlMiddleware is included in the projects' 
    MIDDLEWARE_CLASSES. Any kwargs included in addition to "view", "object", "start" 
    and "end" will be passed to redirect in order to produce the url for the designated
    view.
    
    The default value for "view" is "pp-page", which expects that the kwarg "template" be
    included, passing in the name of the template being linked to.

    For example:

    {% pp_url view="pp-page" object=issue template="filename.html" %}

    {% pp_url template="filename.html" start=0 end=30 %}

    {% pp_url template="filename.html" %}

    >>> from django import template
    >>> from pirate_issues.models import Topic
    >>> topic = Topic(text="A test topic.")
    >>> topic.save()
    >>> load = "{% load pp_url %}"

    >>> ts = "{% pp_url view='pp-page' template='example.html' object=topic %}"
    >>> template.Template(load + ts).render(template.Context({'topic':topic}))
    u'/example.html?_t=...&_o=...'

    >>> ts = "{% pp_url template='example.html' object=topic start=0 end=30 %}"
    >>> template.Template(load + ts).render(template.Context({'topic':topic}))
    u'/example.html?_t=...&_o=...&_s=0&_e=30'

    >>> ts = "{% pp_url template='example.html' start=0 end=30 %}"
    >>> template.Template(load + ts).render(template.Context({'topic':topic}))
    u'/example.html?_s=0&_e=30'

    >>> ts = "{% pp_url view='hello.views.hello_view' start=0 end=30 %}"
    >>> template.Template(load + ts).render(template.Context({'topic':topic}))
    u'/helloworld/?_s=0&_e=30'

    >>> topic.delete()
    '''

    obj = kwargs.pop('object', None)
    start = kwargs.pop('start', None)
    end = kwargs.pop('end', None)
    dimension = kwargs.pop('dimension',None)
    scroll_to = kwargs.pop('scroll_to',None) #argument for javascript scroll_to function
    return_path = kwargs.pop('return_path',None)
    return_query = kwargs.pop('return_query',None)

    pattern = kwargs.pop('view', 'pp-page')

    if (start is None and end is not None) or (start is not None and end is None):
        raise ValueError("If either the 'start' or 'end' argument is specified, then "
                         "both should be specified.") 

    if obj is not None: 
        if isinstance(obj, models.Model):
            content_type = ContentType.objects.get_for_model(obj.__class__)
            rev_kwargs = { 'content_type_id':content_type.pk,
                           'obj_id':str(obj.pk) }

        else:
            raise ValueError("If 'object' argument is specified, it must be of type "
                             "django.models.Model. Specified object is of type '%s.'"
                             % obj.__class__.__name__)
                             
        if scroll_to is not None:
            rev_kwargs['scroll_to'] = scroll_to

        if start is not None and end is not None:
            rev_kwargs['start'] = start
            rev_kwargs['end']   = end
        
        if dimension is not None:
            output = get_reverse(pattern, kwargs, dimension=dimension, **rev_kwargs)
        else:
            output = get_reverse(pattern, kwargs, **rev_kwargs)

    else:
        rev_kwargs = {}
        if start is not None and end is not None:
            rev_kwargs['start'] = start
            rev_kwargs['end']   = end
        if dimension is not None:
            rev_kwargs['dimension'] = dimension
        if return_path is not None and return_query:
            rev_kwargs['returnurl'] = return_path + '?' + return_query
        output = get_reverse(pattern, kwargs, **rev_kwargs)

    #need to append reverse of pattern to user's recently visited list
    
    return output


def get_reverse(pattern, kwargs, content_type_id=None, obj_id=None, start=None, end=None,dimension=None,scroll_to=None,returnurl=None):
    url = reverse(pattern, kwargs=kwargs)
    qs = []
    if content_type_id is not None and obj_id is not None:
        qs.append(TYPE_KEY + "=" + str(content_type_id))
        qs.append(OBJ_KEY + "=" + str(obj_id))
    if start is not None and end is not None:
        qs.append(START_KEY + "=" + str(start))
        qs.append(END_KEY + "=" + str(end))
    if dimension is not None:
        qs.append(DIM_KEY + "=" + str(dimension))
    if scroll_to is not None:
        qs.append(SCROLL_KEY + "=" + str(scroll_to))
    if returnurl is not None:
        returnurl = returnurl.replace('&','%') #replace so we can parse it properly in urls, must replace('%','&') to use in tags
        qs.append(RETURN_KEY + "=" + str(returnurl))

    qs = "?" + "&".join(qs)
    return url + qs


